package es.juanc.threads.concurrent;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

public class NetworkServer {

	private static final Logger log = Logger.getLogger(NetworkServer.class);

	private static final int THREAD_COUNT = 10;
	private static final short LISTEN_PORT = 3434;

	private ServerSocket serverSocket = null;
	private boolean shutdown = false;

	private final ThreadPoolExecutor pool = new ThreadPoolExecutor(
			THREAD_COUNT, THREAD_COUNT, 10, TimeUnit.SECONDS,
			new LinkedBlockingQueue());

	public NetworkServer() throws IOException {
		try {
			serverSocket = new ServerSocket(LISTEN_PORT);
		} catch (IOException e) {
			pool.shutdownNow();
			throw e;
		}
	}

	public void serve() {
		try {
			while (!shutdown) {
				pool.execute(new RequestThread(serverSocket.accept()));
			}
		} catch (Exception e) {
			log.error("Exception while starting request: " + e.getMessage(), e);
		}
	}

	public void shutdown() {
		this.shutdown = true;
		pool.shutdownNow();
		makeFinalConnection();
	}

	private void makeFinalConnection() {
		try {
			Socket clientSocket = new Socket("localhost", LISTEN_PORT);
			clientSocket.close();
		} catch (Exception e) {
		}
	}

	public static void main(String[] args) throws IOException {
		new NetworkServer().serve();
	}
}

class RequestThread implements Runnable {

	private static final Logger log = Logger.getLogger(RequestThread.class);

	private Socket requestSocket = null;

	public RequestThread(Socket requestSocket) {
		this.requestSocket = requestSocket;
	}

	public void run() {

		try {

			BufferedReader bufferedReader = new BufferedReader(
					new InputStreamReader(requestSocket.getInputStream()));

			BufferedWriter bufferedWriter = new BufferedWriter(
					new OutputStreamWriter(requestSocket.getOutputStream()));

			// do some processing�
			String line = bufferedReader.readLine();
			log.debug( "*** procesando la peticion ..." + line );
			//bufferedWriter.write( line );
			// -------------------

			bufferedReader.close();
			bufferedWriter.close();

		} catch (IOException e) {
			log.error("Error communicating with client: " + e.getMessage(), e);
		}
	}
}